﻿using Core.Framework;
using DotNetty.Transport.Channels;
using iTool.ClusterComponent;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;

namespace DotNetty.Framework.BaseTriggers
{
    /// <summary>
    /// 任务处理器
    /// </summary>
    public class WebSocketTaskHandler : AbstractCommandTrigger
    {
        private iToolClusterHostClient iCluster;
        ILogger<WebSocketTaskHandler> logger;
        public WebSocketTaskHandler(ILogger<WebSocketTaskHandler> logger, iToolClusterHostClient cluster)
        {
            this.logger = logger;
            this.iCluster = cluster;
        }

        /// <summary>
        /// 命令事件处理
        /// </summary>
        /// <param name="context"></param>
        /// <param name="message"></param>
        public async Task CommandAsync(IChannelHandlerContext context, AbstractMessage message)
        {
            ConnectorInfo connector = context.GetClientUUID();// ?? new ConnectorInfo() {UUID = "asd" };
            // 是否启用冥等
            bool isIdempotence = connector != null && !string.IsNullOrWhiteSpace(connector?.UUID);
            IRequestIdempotenceService idempotenceService = isIdempotence ? this.iCluster.GetService<IRequestIdempotenceService>(20, connector.UUID) : null;

            //message.Token = "123";
            try
            {
                if (isIdempotence)
                {
                    // 冥等 处理
                    if (!await idempotenceService.StartIfNotExistAsync(message.Token, 10000))
                    {
                        // 说明已经存在相同的token，走缓存。
                        DoWorkResponse cacheResult = await idempotenceService.GetResultAsync(message.Token);
                        await context.WriteAndFlushAsyncOfBinaryAsync(cacheResult).ConfigureAwait(false);
                        return;
                    }
                }

                var channelWorker = this.GetCommandWorker(message, out string value);

                HandleDoWorkingContext workerContext = this.BuildContext(context, message);
                DoWorkResponse response = default;

                try
                {
                    // 未找到匹配的作业管道
                    if (channelWorker == default)
                    {
                        response = this.GetErrorResponseOfNullWorking(workerContext);
                    }
                    else
                    {
                        object[] parameter = channelWorker.IsHavParameter ? new object[] { workerContext, value } : new object[] { workerContext };
                        response = await this.InvokeMethod(channelWorker, parameter).ConfigureAwait(false);
                    }

                    if (isIdempotence)
                    {
                        // 冥等 处理
                        await idempotenceService.SetResultAsync(message.Token, response);
                    }

                    if (response != null)
                    {
                        // 向客户端反馈消息
                        if (context.Channel.Active & context.Channel.IsWritable)
                        {
                            // await context.WriteAndFlushAsyncOfTextAsync(response).ConfigureAwait(false);
                            await context.WriteAndFlushAsyncOfBinaryAsync(response).ConfigureAwait(false);
                        }
                    }
                }
                catch (Exception ex)
                {
                    var error = ex.InnerException;

                    this.logger.LogError(ex, "channelWorker.DoWorking Exception");

                    await context.WriteAndFlushAsyncOfBinaryAsync(new DoWorkResponse
                    {
                        Token = message.Token,
                        Code = CodeResult.INTERFACE_INNER_INVOKE_ERROR,
                        Command = message.CommandText,
                        Info = ex?.InnerException?.Message ?? ex.Message
                    }).ConfigureAwait(false);

                    return;
                }

            }
            catch (Exception ex)
            {
                if (ex is ArgumentNullException timeout)
                {
                    this.logger.LogError(ex, "task time out");
                }
                else
                {
                    this.logger.LogError(ex, "StartNew");
                }
            }
        }

        /// <summary>
        /// 获取返回值 未命中任何任务逻辑
        /// </summary>
        /// <param name="context"></param>
        /// <param name="body">返回参数</param>
        /// <returns></returns>
        protected DoWorkResponse GetErrorResponseOfNullWorking(HandleDoWorkingContext context)
        {
            var response = new DoWorkResponse();
            response.Token = context.Message.Token;
            response.Command = context.Message.CommandText;
            response.Code = CodeResult.PARAMS_IS_INVALID;
            response.RetryDelayedOfSecond = 0;
            response.TaskRunTimeOfMilliseconds = 1;
            return response;
        }


    }
}
